package com.polaris.live.common.mvvm.fragment

import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.annotation.CallSuper
import androidx.annotation.StringRes
import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModelProvider
import com.blankj.utilcode.util.StringUtils
import com.polaris.live.common.mvvm.ext.getVmClazz
import com.polaris.live.common.mvvm.viewmodel.BaseViewModel
import com.polaris.live.common.util.loading.LoadingUtils
import com.polaris.live.common.util.loading.OnCancelListener
import com.polaris.live.common.util.loading.OnDismissListener
import com.polaris.live.translation.R
import java.util.UUID
import java.util.concurrent.ConcurrentLinkedQueue

/**
 * fragmentViewModel是基类  所有fragment的基类
 *
 * @author Created by 半仙 on 2023/7/31/031 15:19
 */
abstract class BaseVmFragment<VM : BaseViewModel> : Fragment() {

    private lateinit var _viewModel: VM
    val mViewModel: VM get() = _viewModel

    private var pageId: String? = null

    //是否第一次加载
    private var isLoadData: Boolean = false

    //是否销毁了view
    private var destroyView: Boolean = false

    private val fragmentLifecycleEventObservers = ConcurrentLinkedQueue<FragmentLifecycleEventObserver>()
    val fragmentDataLoaders = ArrayList<Runnable>()

    /**
     * 当前Fragment绑定的视图布局
     */
    abstract fun layoutId(): Int

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        return inflater.inflate(layoutId(), container, false)
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        _viewModel = createViewModel()

        initView(savedInstanceState)

        createObserver()
        registerDefUIChange()

        if (!isLazyLoad()) {
            initData()
            isLoadData = true
        }
    }

    /**
     *创建viewModel
     */
    private fun createViewModel(): VM {
        return ViewModelProvider(this)[getVmClazz(this)]
    }

    /**
     * 初始化view
     */
    abstract fun initView(savedInstanceState: Bundle?)

    /**
     * 创建观察者
     */
    abstract fun createObserver()

    /**
     * 初始化数据方法
     */
    open fun initData() {}

    /**
     * 是否懒加载
     */
    open fun isLazyLoad(): Boolean = true

    abstract fun showLoading(
        message: String = StringUtils.getString(R.string.loading),
        cancelable: Boolean = false,
        hasShadowBg: Boolean = false,
        cancelTime: Long = 15 * 1000L,
        waitTime: Long = 500L,
        useView: Boolean = true,
        onCancelListener: OnCancelListener? = null,
        onDismissListener: OnDismissListener? = null
    )

    abstract fun dismissLoading(waitTime: Long = 0L)

    override fun onResume() {
        super.onResume()

        lazyLoadData()
    }

    @CallSuper
    override fun onHiddenChanged(hidden: Boolean) {
        super.onHiddenChanged(hidden)

        fragmentLifecycleEventObservers.forEach {
            it.onHiddenChanged(hidden)
        }
    }

    private fun lazyLoadData() {
        if (!isCreated() || isLoadData) {
            return
        }

        isLoadData = true
        initData()

        //加载完成后立即执行
        fragmentDataLoaders.forEach {
            it.run()
        }
        fragmentDataLoaders.clear()
    }

    /**
     * fragment是否初始化成功
     */
    open fun isCreated(): Boolean {
        return this::_viewModel.isInitialized
    }

    /**
     * 是否加载过数据
     */
    fun isLoadData(): Boolean {
        return isLoadData
    }

    override fun onDestroyView() {
        super.onDestroyView()
        destroyView = true
    }

    /**
     * 是否被销毁
     */
    fun isDestroyView(): Boolean {
        return destroyView
    }

    /**
     * 注册 UI 事件
     */
    private fun registerDefUIChange() {
        //显示弹窗
        mViewModel.loadingChange.showDialog.observeInFragment(this) {
            showLoading(
                it.message,
                it.cancelable,
                it.hasShadowBg,
                it.cancelTime,
                it.waitTime,
                it.useView,
                it.onCancelListener,
                it.onDismissListener
            )
        }
        //关闭弹窗
        mViewModel.loadingChange.dismissDialog.observeInFragment(this) {
            dismissLoading(it)
        }
    }

    /**
     * 获取页面唯一id
     */
    fun getPageId(): String {
        val pageId = pageId
        if (pageId != null) {
            return pageId
        }

        return UUID.randomUUID().toString().replace("-", "").also {
            this.pageId = it
        }
    }

    /**
     * 添加fragment隐藏显示监听
     */
    fun addFragmentLifecycleEventObserver(observer: FragmentLifecycleEventObserver) {
        fragmentLifecycleEventObservers.add(observer)
    }

    /**
     * 移除fragment隐藏显示监听
     */
    fun removeFragmentLifecycleEventObserver(observer: FragmentLifecycleEventObserver) {
        fragmentLifecycleEventObservers.remove(observer)
    }

    /**
     * 运行在代码完成加载后
     */
    inline fun withLoaded(crossinline block: () -> Unit) {
        if (isLoadData()) {
            block()
        } else {
            fragmentDataLoaders.add(Runnable {
                block()
            })
        }
    }

    override fun onDestroy() {
        super.onDestroy()

        fragmentLifecycleEventObservers.clear()
    }
}

fun interface FragmentLifecycleEventObserver {

    /**
     * fragment显示隐藏变化，比如当fragment切换时show或者hide时，会触发此方法
     *
     * 注意子fragment需要手动调用
     */
    fun onHiddenChanged(hidden: Boolean)

}

/**
 * 打开等待框
 */
fun BaseVmFragment<*>.showLoading(
    @StringRes message: Int,
    cancelable: Boolean = false,
    hasShadowBg: Boolean = true,
    cancelTime: Long = 15 * 1000L,
    waitTime: Long = 500L,
    useView: Boolean = true,
    onCancelListener: OnCancelListener? = null,
    onDismissListener: OnDismissListener? = null
) {
    LoadingUtils.showLoadingDialog(
        requireContext(),
        getString(message),
        cancelable,
        hasShadowBg,
        cancelTime,
        waitTime,
        useView,
        onCancelListener,
        onDismissListener
    )
}